<?php

namespace App\Models\Plane\PlaneOrders\Repositories;

use App\Models\Orders\Repositories\Interfaces\OrdersRepositoryInterface;
use App\Models\Plane\PlaneOrderPassengers\Repositories\Interfaces\PlaneOrderPassengerRepositoryInterface;
use App\Models\Plane\PlaneOrders\PlaneOrder;
use App\Models\Plane\PlaneOrders\Repositories\Interfaces\PlaneOrderRepositoryInterface;
use App\Trip\Orders\TripOrderState;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;

class UpdateOrderStateBusiness
{
    private PlaneOrder  $current_order;
    private array       $update_data;
    private ?Collection $update_passengers;
    private string      $updated_at;
    private Collection  $current_order_passengers;
    private int         $current_order_passengers_count;
    private int         $update_passengers_count;
    private Collection  $needless_update_passengers; // 不需要更新的乘客 如果要更新的乘客为空 则没有不需要更新的乘客
    private int         $new_order_state;            // 新订单状态

    /**
     * @throws Exception
     */
    public function __construct(PlaneOrder $current_order, array $update_data, ?Collection $update_passengers = null)
    {
        $this->updated_at = Carbon::now()->toDateTimeString();
        $this->setPlaneOrder($current_order)->setUpdateData($update_data)->setUpdatePassengers($update_passengers);
    }

    /**
     * 需要更新的乘客
     *
     * @param Collection|null $update_passengers
     *
     * @return void
     */
    private function setUpdatePassengers(?Collection $update_passengers = null): void
    {
        // 此处加验证 改签 ,退票 均不能为 null
        $this->update_passengers          = $update_passengers;
        $this->update_passengers_count    = $this->update_passengers?->count() ?: 0;
        $this->needless_update_passengers = $this->update_passengers_count > 0 ?
            $this->current_order_passengers
                ->filter(function ($passenger) use ($update_passengers) {
                    $except = collect($update_passengers)->where('passenger_id', $passenger->getPassengerId())
                                                         ->firstWhere('sequence', $passenger->getSequence());
                    if ($except) {
                        return false;
                    }
                    return true;
                }) : collect();
    }

    /**
     * 设置要更新的数据
     *
     * @throws Exception
     */
    private function setUpdateData(array $update_data): static
    {
        $validator = Validator::make($update_data,
            [
                'order_state' => 'required',
            ]);
        if ($validator->fails()) {
            throw new Exception("更新订单状态，参数错误");
        }


        /**
         * 验证子单状态
         */
        if (!in_array($update_data['order_state'], TripOrderState::SUB_ORDER_STATES)) {
            throw new Exception("总单状态需要计算，无法直接更新");
        }
        $this->update_data               = $update_data;
        $this->new_order_state           = $this->update_data['order_state'];
        $this->update_data['updated_at'] = $this->updated_at;
        return $this;
    }

    private function setPlaneOrder(PlaneOrder $order): static
    {
        $this->current_order                  = $order;
        $this->current_order_passengers       = $this->current_order->getPassengers();
        $this->current_order_passengers_count = $this->current_order_passengers->count();
        return $this;
    }

    /**
     * @throws Exception
     */
    public function updateOrderState(): bool
    {
        if ($this->isChangeBusiness()) {
            return $this->updateByChangeBusiness();
        } elseif ($this->isRefundBusiness()) {
            return $this->updateByRefundBusiness();
        }
        return $this->updateNormalBusiness();
    }

    /**
     * 是否是改签相关的业务
     * @ 第一种情况
     * 如果新订单的状态是改签成功 原订单的状态也是 改签成功(已改签)
     * 如果新订单的状态是改签失败 原订单的状态还原 已出票
     * 如果新订单的状态是改签中 和改签待支付 原订单的状态 改签中
     * @ 第二种情况 新改签订单的取消
     * 在没有其他改签子订单的情况下 订单取消后还原总单
     */
    private function isChangeBusiness(): bool
    {
        return $this->current_order->isChangeNew() && (
                in_array($this->new_order_state, TripOrderState::getChangeStates())
                || in_array($this->new_order_state, TripOrderState::canceled_order_states())
            );
    }

    /**
     * 更新改签订单状态
     *
     * @throws Exception
     */
    private function updateByChangeBusiness(): bool
    {

        $planeOrdersRepo    = app(PlaneOrderRepositoryInterface::class);
        $orderPassengerRepo = app(PlaneOrderPassengerRepositoryInterface::class);
        $origin_order_info  = $this->getOriginOrderInfo();
        if (!$origin_order_info) {
            throw new Exception("原订单未找到，new order:{$this->current_order->getOrderSn()}");
        }

        $theChange = new TheChangeOrderStateChanged($this->current_order, $origin_order_info, $this->new_order_state);
        /**
         * 更新原单数据
         */
        $origin_update_data = [
            'order_state' => $theChange->getOriginOrderState(),
            'change_flag' => $theChange->getOriginOrderChangeFlag(),
            'is_show'     => $theChange->getOriginOrderShowState(),
            'updated_at'  => $this->updated_at,
        ];
        $planeOrdersRepo->update($origin_update_data, $origin_order_info);
        $needUpdateOriginOrderPassengers          = $theChange->getNeedUpdateOriginPassengers();
        $needUpdateOriginOrderPassengerOrderState = $theChange->getNeedUpdateOriginPassengerOrderState();
        foreach ($needUpdateOriginOrderPassengers as $origin_order_passenger) {
            $orderPassengerRepo->updatePassenger($origin_order_passenger, [
                'order_state' => $needUpdateOriginOrderPassengerOrderState,
                "updated_at"  => $this->updated_at,
            ]);
        }
        /**
         * 更新改签新单数据
         */
        $commonOrderSubOrder              = $theChange->getCommonOrderSubOrder();
        $change_order_state               = $theChange->getChangeOrderState();
        $this->update_data['order_state'] = $change_order_state;
        $this->update_data['is_show']     = $theChange->getChangeOrderShowState();
        if ($theChange->getChangeOrderWillDelete()) {
            $this->update_data['delete_state'] = $theChange->getChangeOrderDeleteState();
            $this->update_data['deleted_at']   = $this->updated_at;
            $this->update_data['delete_desc']  = "取消改签，删除";
            $this->update_data['is_show']      = 0;
        }
        /**
         * 当前订单的状态
         */
        $this->updateCurrentOrderPassengerOrderState();
        $res = $planeOrdersRepo->update($this->update_data, $this->current_order);
        if ($last = $theChange->getLastOtherChangedOrder()) {
            $planeOrdersRepo->update(['is_show' => $theChange->getLastChangedOrderShowState()], $last);
        }

        /**
         * 更新总单数据
         */
        $common_update_data = [
            'updated_at' => $this->updated_at,
        ];
        $common_order_state = $theChange->getCommonOrderState();
        if ($common_order_state != $change_order_state) {
            $common_update_data['order_state'] = $common_order_state;
        }
        $this->createOrUpdateCommonOrder($commonOrderSubOrder, $common_update_data);
        return $res;
    }

    private function getOriginOrderInfo(): ?PlaneOrder
    {
        if (!$this->current_order->getOriginOrderSn()) {
            return null;
        }
        return $this->current_order->getOriginOrderInfo();
    }

    private function updateCurrentOrderPassengerOrderState(): void
    {
        /**
         * 只更新 传入的乘客状态,如果传入乘客为空,则更新当前订单的乘客
         */
        $orderPassengerRepo = app(PlaneOrderPassengerRepositoryInterface::class);
        if (!$this->update_passengers) {
            foreach ($this->current_order_passengers as $passenger) {
                $orderPassengerRepo->updatePassenger($passenger, [
                    'order_state' => $this->new_order_state,
                    'updated_at'  => $this->updated_at,
                ]);
            }
        } else {
            foreach ($this->update_passengers as $updatePassenger) {
                $passenger = $this->current_order_passengers->where('passenger_id', $updatePassenger['passenger_id'])
                                                            ->firstWhere('sequence');
                $passenger && $orderPassengerRepo->updatePassenger($passenger, [
                    'order_state' => $this->new_order_state,
                    'updated_at'  => $this->updated_at,
                ]);
            }
        }
    }

    /**
     * @param PlaneOrder $order
     * @param array      $data
     *
     * @return void
     */
    private function createOrUpdateCommonOrder(PlaneOrder $order, array $data): void
    {
        $common_update_data = [
            'updated_at' => $this->updated_at,
        ];

        if (!empty($data)) {
            $common_update_data = array_merge($common_update_data, $data);
        }

        $orderRepo = app(OrdersRepositoryInterface::class);
        // 退款业务下 如果当前订单是改签原单,总单就保持原样
        $commonOrder = $order;
        if ($this->isRefundBusiness() && $order->isChangeOrigin()) {
            $commonOrderInfo = $orderRepo->findOneByPlaneOrderTrip($commonOrder);
            // 仅更新总单状态
            $orderRepo->updateOrder($commonOrderInfo, $common_update_data);
            return;
        }
        $orderRepo->createOrUpdateOrder($commonOrder, $common_update_data);
    }

    /**
     * 是否是退款相关的业务
     * 含退款中 和 退款成功
     *
     * @return bool
     */
    private function isRefundBusiness(): bool
    {
        return in_array($this->new_order_state, [
                TripOrderState::ORDER_STATE_REFUNDING,
                TripOrderState::ORDER_STATE_REFUNDED,
                TripOrderState::ORDER_STATE_REFUND_FAILED,
            ]
        );
    }

    /**
     * 退款业务
     *
     * @return bool
     */
    private function updateByRefundBusiness(): bool
    {
        // 退票只能单乘客退票 如果当前订单是多乘客,
        $isMorePassengers = $this->current_order_passengers_count > 1;
        if (!$isMorePassengers) {
            // 当前订单只有一个乘客的情况  直接走 普通更新逻辑 ,单乘客没有多余的状态计算直接更新即可
            return $this->updateNormalBusiness();
        }

        /**
         * 订单状态和总单状态默认 为变更的状态值  new_order_state
         */
        $planeOrdersRepo    = app(PlaneOrderRepositoryInterface::class);
        $order_state        = $this->new_order_state;
        $common_order_state = $this->new_order_state;
        switch ($this->new_order_state) {
            case TripOrderState::ORDER_STATE_REFUNDING:
                // 如果是退票中状态 此时走普通逻辑即可 因为退票中不参与多余的状态计算
                return $this->updateNormalBusiness();
            case TripOrderState::ORDER_STATE_REFUNDED:
            case TripOrderState::ORDER_STATE_REFUNDED_PART:
                /**
                 * 多乘客的情况
                 * 如果都选择退票 且成功 显示 退票成功
                 * 如果部分乘客 退票 显示部分退票成功
                 */
                $order_state                    = TripOrderState::ORDER_STATE_REFUNDED_PART;
                $common_order_state             = TripOrderState::ORDER_STATE_REFUNDED_PART;
                $other_passenger_refunded_count = 0;
                foreach ($this->needless_update_passengers as $other_passenger) {
                    // 如果其他乘客有未退票状态的跳出 ,并说明有说明 部分退票成功 订单状态标记为 退票成功
                    if ($other_passenger->getOrderState() != TripOrderState::ORDER_STATE_REFUNDED) {
                        $order_state        = TripOrderState::ORDER_STATE_REFUNDED;
                        $common_order_state = TripOrderState::ORDER_STATE_REFUNDED;
                        break;
                    }
                    // 全都退票成功的情况
                    if ($other_passenger->getOrderState() == TripOrderState::ORDER_STATE_REFUNDED) {
                        $other_passenger_refunded_count++;
                        if ($other_passenger_refunded_count == $this->current_order_passengers_count - $this->update_passengers_count) {
                            $order_state        = TripOrderState::ORDER_STATE_REFUNDED;
                            $common_order_state = TripOrderState::ORDER_STATE_REFUNDED;
                        }
                    }
                }
                // 如果是改签新单  并且新状态为部分退款,订单状态显示为订单改签有退款
                if ($this->current_order->isChangeNew() && $order_state == TripOrderState::ORDER_STATE_REFUNDED_PART) {
                    $order_state        = TripOrderState::ORDER_STATE_CHANGED_HAS_REFUNDED;
                    $common_order_state = TripOrderState::ORDER_STATE_CHANGED_HAS_REFUNDED;
                }
                break;
            case TripOrderState::ORDER_STATE_REFUND_FAILED:
                // 多乘客的情况
                $order_state                  = TripOrderState::ORDER_STATE_REFUND_PART_FAILED;
                $common_order_state           = TripOrderState::ORDER_STATE_REFUND_PART_FAILED;
                $other_passenger_failed_count = 0;
                foreach ($this->needless_update_passengers as $other_passenger) {
                    // 如果其他乘客 有未退票状态的 跳出 并说明 有退票 反之全都退票 说明 部分退票成功
                    if ($other_passenger->getOrderState() != TripOrderState::ORDER_STATE_REFUND_FAILED) {
                        $order_state        = TripOrderState::ORDER_STATE_REFUNDED_PART;
                        $common_order_state = TripOrderState::ORDER_STATE_REFUNDED_PART;
                        break;
                    }
                    // 全都退票成功的情况
                    if ($other_passenger->getOrderState() == TripOrderState::ORDER_STATE_REFUND_FAILED) {
                        $other_passenger_failed_count++;
                        if ($other_passenger_failed_count == $this->current_order_passengers_count - $this->update_passengers_count) {
                            $order_state        = TripOrderState::ORDER_STATE_REFUND_FAILED;
                            $common_order_state = TripOrderState::ORDER_STATE_REFUND_FAILED;
                        }
                    }
                }
                break;
        }

        $this->update_data['order_state'] = $order_state;
        $res                              = $planeOrdersRepo->update($this->update_data, $this->current_order);
        /**
         * 更新当前订单乘客状态
         */
        $this->updateCurrentOrderPassengerOrderState();
        $common_update_data = [
            'updated_at' => $this->updated_at,
        ];
        if ($common_order_state != $order_state) {
            $common_update_data['order_state'] = $common_order_state;
        }
        $this->createOrUpdateCommonOrder($this->current_order, $common_update_data);
        return $res;
    }

    private function updateNormalBusiness(): bool
    {
        /**
         * 更新当前订单乘客状态
         */
        $planeOrdersRepo = app(PlaneOrderRepositoryInterface::class);
        $this->updateCurrentOrderPassengerOrderState();
        $res = $planeOrdersRepo->update($this->update_data, $this->current_order);
        $this->createOrUpdateCommonOrder($this->current_order, []);
        return $res;
    }

}